{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7c4cbf55-4267-46a5-b18f-ea6fd703d549",
   "metadata": {},
   "outputs": [],
   "source": [
    "pip install langchain langchain_community PyPDF2 langchain_milvus langgraph"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2bdbd7c9-192b-42e9-b10e-cadd78fb81bd",
   "metadata": {},
   "source": [
    "# 文档切分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "4273dafa-08e5-4b48-bf84-a2a1050e7ec6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-07-25T06:05:11.445554Z",
     "iopub.status.busy": "2025-07-25T06:05:11.445477Z",
     "iopub.status.idle": "2025-07-25T06:05:20.710714Z",
     "shell.execute_reply": "2025-07-25T06:05:20.708678Z",
     "shell.execute_reply.started": "2025-07-25T06:05:11.445554Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Document(metadata={'pk': 459601663076628501}, page_content='第一章山边小村  \\n二愣子睁大着双眼，直直望着茅草和烂泥糊成的黑屋顶，身上盖着的旧棉被，已呈深黄色，\\n看不出原来的本来面目，还若有若无的散着淡淡的霉味。  \\n在他身边紧挨着的另一人，是二哥韩铸，酣睡的十分香甜，从他身上不时传来轻重不一的阵\\n阵打呼声。  \\n离床大约半丈远的 地方，是一堵黄泥糊成的土墙，因为时间过久，墙壁上裂开了几丝不起眼\\n的细长口子，从这些裂纹中，隐隐约约的传来韩母唠唠叨叨的埋怨声，偶尔还掺杂着韩父，\\n抽旱烟杆的“啪嗒”“啪嗒”吸允声。  \\n二愣子缓缓的闭上已有些涩的双目，迫使自己尽早进入深深的睡梦中。他心里非常清楚，再\\n不老实入睡的话，明天就无法早起些了，也就无法和其他约好的同伴一起进山拣干柴。  \\n二愣子姓韩名立，这么像模像样的名字 ,他父母可起不出来，这是他父亲用两个粗粮制成的\\n窝头，求村里老张叔给起的名字。  \\n老张叔年轻时， 曾经跟城里的有钱人当过几年的伴读书童， 是村里唯一认识几个字的读书人，\\n村里小孩子的名字，倒有一多半是他给起的。  \\n韩立被村里人叫作“二愣子”，可人并不是真愣真傻，反而是村中屈一指的聪明孩子，但就像\\n其他村中的孩子一样， 除了家里人外， 他就很少听到有人正式叫他名字“韩立”， 倒是“二愣子”\\n“二愣子”的称呼一直伴随至今。  \\n而之所以被人起了个“二愣子”的绰号，也只不过是因为村里已有一个叫“愣子”的孩子了。')]\n"
     ]
    }
   ],
   "source": [
    "from PyPDF2 import PdfReader\n",
    "from langchain_core.documents import Document\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "\n",
    "\n",
    "def pdf_read(pdf_doc):\n",
    "    text = \"\"\n",
    "    for pdf in pdf_doc:\n",
    "        pdf_reader = PdfReader(pdf)\n",
    "        for page in pdf_reader.pages:\n",
    "            text += page.extract_text()\n",
    "    return text\n",
    "# 返回值content将包含该 PDF 文件的所有文本内容。\n",
    "content = pdf_read(['./data/凡人修仙传第一章.pdf'])\n",
    "# Document 对象，其属性 page_content 被设置为之前从 PDF 文件中提取的文本 content。\n",
    "documents = [Document(page_content=content)]\n",
    "\n",
    "chunk_size = 600\n",
    "chunk_overlap = 200\n",
    "# 使用 LangChain 的 RecursiveCharacterTextSplitter根据指定的块大小和重叠部分将文档文本分割成多个较小的部分，完成文本切分。\n",
    "text_splitter = RecursiveCharacterTextSplitter(\n",
    "    chunk_size=chunk_size, chunk_overlap=chunk_overlap\n",
    ")\n",
    "\n",
    "# 切分\n",
    "splits = text_splitter.split_documents(documents)\n",
    "# print(splits)\n",
    "\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "import os\n",
    "os.environ[\"USER_AGENT\"] = \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\"\n",
    "API_KEY = \"hk-xxx\";\n",
    "BASE_URL = \"https://api.openai-hk.com/v1\";\n",
    "os.environ[\"OPENAI_API_KEY\"] = API_KEY\n",
    "os.environ[\"OPENAI_API_BASE\"] = BASE_URL\n",
    "\n",
    "embeddings = OpenAIEmbeddings(\n",
    "    model=\"text-embedding-3-small\",\n",
    ")\n",
    "\n",
    "text = \"第一章山边小村 \\n 二愣子睁大着双眼，直直望着茅草和烂泥糊成的黑屋顶，身上盖着的旧棉被，已呈深黄色。\"\n",
    "\n",
    "single_vector = embeddings.embed_query(text)\n",
    "# print(str(single_vector))  # 显示前词向量的表示 1536维度\n",
    "\n",
    "from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
    "from langchain_community.document_loaders import WebBaseLoader\n",
    "from langchain_milvus import Milvus\n",
    "\n",
    "\n",
    "# 添加到向量数据中\n",
    "vectorstore = Milvus.from_documents(\n",
    "    documents=splits,\n",
    "    collection_name=\"langChainRag\",\n",
    "    embedding=embeddings,\n",
    "    connection_args={\n",
    "        \"uri\": \"https://xxx.serverless.aws-eu-central-1.cloud.zilliz.com\",\n",
    "        \"user\": \"db_xxx\",\n",
    "        \"password\": \"xxx\",\n",
    "    }\n",
    ")\n",
    "\n",
    "# 接入LLM测试\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.messages import HumanMessage\n",
    "\n",
    "from langchain.prompts import PromptTemplate\n",
    "from langchain import hub\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "model = ChatOpenAI(model=\"gpt-4o-mini\")\n",
    "\n",
    "# 提示词模板\n",
    "prompt = PromptTemplate(\n",
    "    template=\"\"\"你是一个智能问答助手. 使用以下检索到的上下文片段来回答问题。 如果你不知道答案，直接说不知道即可。\n",
    "    最多用三句话，回答要简明扼要:\n",
    "    问题: {question} \n",
    "    内容: {context} \n",
    "    回答: \n",
    "    \"\"\",\n",
    "    input_variables=[\"question\", \"documents\"],\n",
    ")\n",
    "\n",
    "# 构建传统的RAG Chain\n",
    "rag_chain = prompt | model | StrOutputParser()\n",
    "# 问题\n",
    "question = \"韩立是的名字是谁起的？\"\n",
    "# 构建检索器\n",
    "retriever = vectorstore.as_retriever(search_kwargs={\"k\": 1})\n",
    "\n",
    "# 执行检索\n",
    "docs = retriever.invoke(\"question\")\n",
    "print(docs)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5bb114b-bbd8-49a1-a3ad-a8377a5a7a44",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-07-25T05:49:43.786709Z",
     "iopub.status.busy": "2025-07-25T05:49:43.785673Z",
     "iopub.status.idle": "2025-07-25T05:49:46.473945Z",
     "shell.execute_reply": "2025-07-25T05:49:46.472927Z",
     "shell.execute_reply.started": "2025-07-25T05:49:43.786709Z"
    }
   },
   "source": [
    "# 接入LLM测试\n",
    "```python\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.messages import HumanMessage\n",
    "model = ChatOpenAI(model=\"gpt-4o-mini\")\n",
    "#res=model.invoke([HumanMessage(content=\"你好，请写句诗剧赞美盛夏\")])\n",
    "#print(res.content)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "a77847e8-ebd2-4ea7-a2a4-25292724d139",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-07-25T06:08:01.764113Z",
     "iopub.status.busy": "2025-07-25T06:08:01.763119Z",
     "iopub.status.idle": "2025-07-25T06:08:03.301384Z",
     "shell.execute_reply": "2025-07-25T06:08:03.299778Z",
     "shell.execute_reply.started": "2025-07-25T06:08:01.764113Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "韩立的名字是他的父亲求村里老张叔给起的。老张叔是村里唯一的读书人，曾经认识几个字。韩立被朋友们称为“二愣子”，但这只是个绰号。\n"
     ]
    }
   ],
   "source": [
    "generation = rag_chain.invoke({\"context\": docs, \"question\": question})\n",
    "print(generation)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain",
   "language": "python",
   "name": "langchain"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
